using System;
using System.Collections.Generic;
using UnityEngine;

namespace Framework
{
    public class EntityLogic
    {
        public static Vector3 HidePosition = Vector3.one * 1000f;
        public string Path { get; private set; }
        public int InstanceID { get; private set; }
        public bool IsGameObjectEnabled { get; private set; }
        public bool FixedUpdateEnabled { get; protected set; }
        public bool Removed { get; private set; }
        public int ChildCount { get; private set; }
        public EntityLogic Parent { get; private set; }
        protected GameObject GameObject { get; private set; }

        public Type Type;
        public bool Removing;
        private GameObject _gameObject;
        private object _sign;
        private List<EntityLogic> _childs;
        private Transform _originalParent;
        public void SetLogicType(Type value)
        {
            this.Type = value;
        }
        public void LogicAwake(object sign, string path, int id)
        {
            if (_sign != null) return;
            _sign = sign;
            this.Path = path;
            this.InstanceID = id;
            OnAwake();
            Removed = false;
            Removing = false;
        }
        public void LogicDestroy(object sign)
        {
            if (_sign != sign) return;
            if (!Removed) return;
            if (_gameObject != null)
            {
                IsGameObjectEnabled = false;
                GameObject.Destroy(_gameObject);
                _gameObject = null;
            }
            _childs = null;
            _originalParent = null;
        }
        public void LogicRemove(object sign)
        {
            if (Removed) return;
            if (_sign != sign) return;
            OnDestroy();
            Removed = true;
            if (Parent != null)
            {
                Parent.RemoveChild(this);
                Parent = null;
            }
            if (_gameObject != null)
            {
                if (_gameObject.transform.parent != _originalParent)
                {
                    _gameObject.transform.SetParent(_originalParent);
                }
                _gameObject.transform.position = HidePosition;
            }
            if (_childs != null)
            {
                var len = _childs.Count;
                while (len-- > 0)
                {
                    var item = _childs[len];
                    item.LogicRemove(sign);
                }
                _childs.Clear();
            }
            ChildCount = 0;
            Removing = false;
        }
        public void SetGameObject(object sign, GameObject target, Transform container)
        {
            if (_sign != sign) return;
            _gameObject = target;
            _originalParent = container;
            if (Parent == null)
            {
                GameObject = _gameObject;
                IsGameObjectEnabled = GameObject != null;
            }
        }
        public void SetGameObject(object sign)
        {
            if (_sign != sign) return;
            _gameObject = null;
            this.Removing = true;
        }
        public bool GetGameObjectEnabled(object sign)
        {
            if (_sign != sign) return true;
            return _gameObject != null;
        }
        public void LogicStart(object sign)
        {
            if (_sign != sign) return;
            Removed = false;
            Removing = false;
            SetParent(Parent);
            OnStart();
        }
        public void AddChild(EntityLogic value)
        {
            if (value == null) return;
            if (value.Parent == this) return;
            if (_childs == null)
            {
                _childs = new List<EntityLogic>();
            }
            if (_childs.Contains(value)) return;
            if (value.Parent != null)
            {
                value.Parent.RemoveChild(value);
            }
            value.SetParent(this);
            _childs.Add(value);
            ChildCount = _childs.Count;
        }
        public void RemoveChild(EntityLogic value)
        {
            if (value == null) return;
            if (_childs == null)
            {
                return;
            }
            if (value.Parent != this) return;
            value.SetParent(null);
            _childs.Remove(value);
            ChildCount = _childs.Count;
        }

        public void SetRemoveing(object sign)
        {
            Removing = true;
        }
        public void Update(object sign, float deltaTime, float unscaledDeltaTime)
        {
            if (_sign != sign) return;
            OnUpdate(deltaTime, unscaledDeltaTime);
            if (_childs != null)
            {
                var len = _childs.Count;
                for (int i = 0; i < len; i++)
                {
                    var item = _childs[i];
                    item.Update(sign, deltaTime, unscaledDeltaTime);
                }
            }
        }
        public void FixedUpdate(object sign, float deltaTime, float unscaledDeltaTime)
        {
            if (_sign != sign) return;
            OnFixedUpdate(deltaTime, unscaledDeltaTime);
            if (_childs != null)
            {
                var len = _childs.Count;
                for (int i = 0; i < len; i++)
                {
                    var item = _childs[i];
                    item.FixedUpdate(sign, deltaTime, unscaledDeltaTime);
                }
            }
        }


        private void SetParent(EntityLogic value)
        {
            this.Parent = value;
            if (!IsGameObjectEnabled) return;
            var parent = _originalParent;
            if (value != null)
            {
                if (!value.IsGameObjectEnabled) return;
                parent = value._gameObject.transform;
            }
            if (parent == _originalParent) return;
            _gameObject.transform.SetParent(parent);
        }
        protected virtual void OnAwake()
        {

        }
        protected virtual void OnUpdate(float deltaTime, float unscaledDeltaTime)
        {

        }
        protected virtual void OnDestroy()
        {
            if (IsGameObjectEnabled && _gameObject != null)
            {
                _gameObject.transform.position = HidePosition;
            }
        }
        protected virtual void OnFixedUpdate(float deltaTime, float unscaledDeltaTime)
        {

        }
        protected virtual void OnStart()
        {

        }
    }
}